/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.brainstretch.ejb.managers;

import java.util.ArrayList;
import java.util.EnumMap;
import java.util.List;
import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.ejb.LocalBean;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.PersistenceUnit;
import javax.persistence.Query;
import org.brainstretch.ejb.session.NormalizationManager;
import org.brainstretch.models.User;
import org.brainstretch.models.document.DocumentVector;
import org.brainstretch.models.document.Posting;
import org.brainstretch.models.quizzes.Quiz;
import org.brainstretch.recommend.Heap;
import org.brainstretch.recommend.ProfileDimension;
import org.brainstretch.recommend.ProfileVector;
import org.brainstretch.recommend.RecommendItem;

/**
 *
 * @author mrodaitis
 */
@Stateless
@LocalBean
public class RecommendationManager {
    
    @PersistenceUnit(unitName="BrainStretchPU")
    EntityManagerFactory entityManagerFactory;
    
    @EJB
    NormalizationManager normalizationManager;
    
    private static final double NON_RELEVANT_W = 0.15;
    private static final double PROFILE_WEIGHT = 0.5;
    private static final double DOC_WEIGHT = 0.5;
    
    public DocumentVector getVectorFor(Quiz quiz){
        EntityManager entityManager = entityManagerFactory.createEntityManager();
        DocumentVector queryVect = getVectorFor(quiz, entityManager);
        entityManager.close();
        return queryVect;
    }
    
    private DocumentVector getVectorFor(Quiz quiz, EntityManager entityManager){
        
        Query findPostings = entityManager.createQuery("SELECT posting FROM Posting posting JOIN posting.quiz quiz WHERE quiz.id = ?1");
        List<Posting> origPostings = findPostings.setParameter(1, quiz.getId()).getResultList();
        DocumentVector queryVect = new DocumentVector(origPostings);
        return queryVect;
    }
    
    
    public List<Quiz> getSimilarQuizzes(Quiz quiz, int numQuizzes){
        EntityManager entityManager = entityManagerFactory.createEntityManager();
       
        EnumMap<ProfileDimension, Double> normMap = normalizationManager.getNormalizationMap();
        
        DocumentVector queryVect = getVectorFor(quiz, entityManager);
        ProfileVector profileVector = new ProfileVector(quiz.getProfile());
        
        profileVector.normalize(normMap);
        List<Long> ignore = new ArrayList<Long>();
        ignore.add(quiz.getId());
        List<Quiz> quizzes = getSimilarQuizzes(queryVect, profileVector, ignore, numQuizzes,  normMap, entityManager);
        entityManager.close();
        return quizzes;
    }    
    
    public List<Quiz> rejectRecommended(Quiz original, Quiz rejected, User user, int numQuizzez){
        EntityManager entityManager = entityManagerFactory.createEntityManager();
        
        List<Long> ignore = new ArrayList<Long>();
        ignore.add(original.getId());
        ignore.add(rejected.getId());
        
        EnumMap<ProfileDimension, Double> normMap = normalizationManager.getNormalizationMap();
        
        DocumentVector queryVector = getVectorFor(original, entityManager);
        DocumentVector nonRelevantVector = getVectorFor(rejected, entityManager);
        ProfileVector quizProfileVector = new ProfileVector(original.getProfile());
        
        quizProfileVector.normalize(normMap);
        
        nonRelevantVector.scale(NON_RELEVANT_W* -1);
        queryVector.add(nonRelevantVector);
        
        List<Quiz> quizzes =  getSimilarQuizzes(queryVector, quizProfileVector, ignore, numQuizzez, normMap, entityManager);
        entityManager.close();
        return quizzes;
    }
    
    
    private List<Quiz> getSimilarQuizzes(DocumentVector queryVector, ProfileVector profileVect, List<Long> ignoreQuizIds, int numQuizzes, EnumMap<ProfileDimension, Double> normMap, EntityManager entityManager){
        
        Query findPostings = entityManager.createQuery("SELECT posting FROM Posting posting JOIN posting.quiz quiz WHERE quiz.id = ?1");        
        //TODO optimize
        Query findQuizzes = entityManager.createQuery("SELECT quiz FROM Quiz quiz WHERE quiz.id NOT IN ?1");
        
        List<Quiz> activeSet = findQuizzes.setParameter(1, ignoreQuizIds).getResultList();
        Heap<RecommendItem> recHeap = new Heap<RecommendItem>();
        
        for(Quiz findQuiz: activeSet){
            List<Posting> postings = findPostings.setParameter(1, findQuiz.getId()).getResultList();
            DocumentVector quizVect = new DocumentVector(postings);            
            double docScore = queryVector.cosineSimilarity(quizVect);
            
            ProfileVector pVect = new ProfileVector(findQuiz.getProfile());
            pVect.normalize(normMap);
            double profScore = pVect.cosineSimilarity(profileVect);
            
            double score = DOC_WEIGHT * docScore + PROFILE_WEIGHT * profScore;
            
            System.out.println(findQuiz.getTitle()+": DocScore: "+docScore+" | profScore: "+profScore + " | result: "+score);
            RecommendItem item = new RecommendItem(quizVect, pVect, score, findQuiz);
            recHeap.insert(item);
        }
        
        
        List<Quiz> recQuizzes = new ArrayList<Quiz>();
        for(int i = 0; i<numQuizzes && recHeap.size() > 0; i++){
            Quiz recQuiz = recHeap.remove().getQuiz();
            recQuizzes.add(recQuiz);
        }
        return recQuizzes;
    }
}
